#include "OpenCCUtil.h"
#include "configmanager.h"

#include <QFile>
#include <QDir>
#include <QDebug>

OpenCCUtil* OpenCCUtil::m_instance = nullptr;
QMutex OpenCCUtil::m_instanceMutex;

OpenCCUtil::OpenCCUtil(QObject *parent) : QObject(parent)
{
	// config read
	ConfigManager* config = ConfigManager::getInstance();
	m_dictPath = config->getOpenCCDictPath();

	// init OpenCC
	if (!initOpenCC()) {
		QString err = "简繁转换功能初始化失败，请检查opencc.dll或词典路径";
        emit initFailed(err);
        qCritical() << "[OpenCCUtil]" << err;
	}

	// listen config changes
	connect(config, &ConfigManager::configChanged, this, [this](ConfigGroup group, const QString& key, const QVariant& value) {
		if (group != InputMethodGroup || key != "OpenCCDictPath") return;

        QString newPath = value.toString();
        setDictPath(newPath);
        if (!initOpenCC()) {
            QString err = "词典路径更新失败，已回退到默认路径";
            emit initFailed(err);
            m_dictPath = m_defaultDictPath;
            initOpenCC();  // 重新初始化默认路径
        }
	});
}

OpenCCUtil *OpenCCUtil::getInstance(QObject *parent)
{
	// 双重检查锁定
	if (!m_instance) {
		QMutexLocker locker(&m_instanceMutex);
		if (!m_instance) {
			m_instance = new OpenCCUtil(parent);
		}
	}
	return m_instance;
}

OpenCCUtil::~OpenCCUtil()
{
	// uninstall .dll
	if (m_openccLib.isLoaded())	{
        m_openccLib.unload();
        qInfo() << "[OpenCCUtil] 已卸载opencc.dll";
    }
}

QString OpenCCUtil::convert(const QString &text, ConvertDirection direction)
{
	if (!m_isInitialized || text.isEmpty()) {
		return text;
	}
	// 对应方向的配置文件path
	QString configPath = getConfigPathByDirection(direction);
	if (configPath.isEmpty()) {
		qWarning() << "[OpenCCUtil] 不支持的转换方向";
		return text;
	}

	// 创建OpenCC实例
	void* opencc = m_openccCreate(configPath.toUtf8().constData());
	if (!opencc) {
		qWarning() << "[OpenCCUtil] 创建实例fail configPath: " << configPath;
		return text;
	}
	// 转换文本  QString→UTF-8→转换→QString
	QByteArray inputData = text.toUtf8();
	char* ans = m_openccConvert(opencc, inputData.constData(), inputData.size());
	QString convertedText = QString::fromUtf8(ans);

	// delete
	m_openccFree(ans);
	m_openccDestroy(opencc);
	qDebug() << "[OpenCCUtil] 转换完成：" << text << "→" << convertedText;
    return convertedText;
}

void OpenCCUtil::setDictPath(const QString &path)
{
	if (path.isEmpty())		return;
	m_dictPath = path;
	// check 有效 无效则default
	if (!validateDictPath(m_dictPath)) {
        m_dictPath = m_defaultDictPath;
        qWarning() << "[OpenCCUtil] 词典路径无效，回退默认：" << m_defaultDictPath;
    }
}

bool OpenCCUtil::initOpenCC()
{
	// 从thirdparty\opencc\lib load
	QString dllPath = QDir::currentPath() + "/thirdparty/opencc/lib/opencc.dll";
	if (!QFile::exists(dllPath)) {
		qWarning() << "[OpenCCUtil] opencc.dll不存在：" << dllPath;
        return false;
	}

	m_openccLib.setFileName(dllPath);
	if (!m_openccLib.load()) {
		qWarning() << "[OpenCCUtil] 加载opencc.dll失败：" << m_openccLib.errorString();
		return false;
	}

	// 解析函数指针
	m_openccCreate = (OpenCC_Create)m_openccLib.resolve("opencc_create");
    m_openccConvert = (OpenCC_ConvertUTF8)m_openccLib.resolve("opencc_convert_utf8");
    m_openccDestroy = (OpenCC_Destroy)m_openccLib.resolve("opencc_destroy");
    m_openccFree = (OpenCC_Free)m_openccLib.resolve("opencc_free");

	if (!m_openccCreate || !m_openccConvert || !m_openccDestroy || !m_openccFree) {
		qWarning() << "[OpenCCUtil] 获取OpenCC函数指针失败：" << m_openccLib.errorString();
		m_openccLib.unload();
		return false;
	}

	// check dict path
	if (!validateDictPath(m_dictPath)) {
        m_dictPath = m_defaultDictPath;
        if (!validateDictPath(m_dictPath)) {
            qWarning() << "[OpenCCUtil] 默认词典路径无效：" << m_defaultDictPath;
            return false;
        }
    }

    m_isInitialized = true;
    qInfo() << "[OpenCCUtil] 初始化成功，词典路径：" << m_dictPath;
    return true;
}

QString OpenCCUtil::getConfigPathByDirection(ConvertDirection direction)
{
	// get path 然后去拼接
	QString configFileName = m_dirToConfig.value(direction);
	if (configFileName.isEmpty())	return "";

	return QDir(m_dictPath).filePath(configFileName);
}

bool OpenCCUtil::validateDictPath(const QString &path)
{
	QDir dictDir(path);
	if (!dictDir.exists()) {
		qWarning() << "[OpenCCUtil] 词典路径不存在：" << path;
        return false;
	}
	// json 要存在  核心配置文件校验（s2t.json为简体→台繁基础文件）
	QString testConfig = dictDir.filePath("s2t.json");
    if (!QFile::exists(testConfig)) {
        qWarning() << "[OpenCCUtil] 词典路径缺少核心配置文件：" << testConfig;
        return false;
    }
    return true;
}
